/*
 * This file is part of b.AMP.
 *
 * b.AMP is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * b.AMP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with b.AMP.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "message_ack.hpp"
#include "message_target.hpp"
#include "message_channel.hpp"

#include <boost/foreach.hpp>


bamp::MessageChannel::MessageChannel()
    : m_targets(),
      m_targetsMutex()
{
    // Nothing here
}


bamp::MessageChannel::~MessageChannel()
{
    // Nothing here
}


void bamp::MessageChannel::addTarget(MessageTarget& target)
{
    boost::mutex::scoped_lock lock(m_targetsMutex);

    // Attach the message target only if it is not already attached
    TargetVec::const_iterator it;
    it = std::find(m_targets.begin(), m_targets.end(), &target);
    if (it == m_targets.end()) {
        m_targets.push_back(&target);
        lock.unlock();    
    }

}


void bamp::MessageChannel::removeTarget(MessageTarget& target)
{
    boost::mutex::scoped_lock lock(m_targetsMutex);

    // Remove the target from the target vector
    TargetVec::iterator it;
    it = std::remove(m_targets.begin(), m_targets.end(), &target);
    if (it != m_targets.end()) {
        m_targets.erase(it, m_targets.end());
        lock.unlock();
    }
}


void bamp::MessageChannel::send(const Message& message, MessageAck ack)
{
    boost::mutex::scoped_lock lock(m_targetsMutex);

    // Use the existing ack
    BOOST_FOREACH(MessageTarget* t, m_targets) {
        t->send(message, ack);
    }
}


bamp::MessageAck bamp::MessageChannel::send(const Message& message)
{
    boost::mutex::scoped_lock lock(m_targetsMutex);

    // Create a new ack. The caller can use it to track the status of a
    // message after it has been dispatched.
    MessageAck ack(m_targets.size());
    BOOST_FOREACH(MessageTarget* t, m_targets) {
        t->send(message, ack);
    }

    return ack;
}
